#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdbool.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>


#define SIZE_CMD 256
#define LINE_SIZE 32
#define DELIM " "
#define MYENV_NUM 5
#define EXEC_FAIL -1

int Exit_code=0;
int Sig=0;//不存在0号信号
int Env_Num=0;//最多五个<5
char Pwd[LINE_SIZE];
char Myenv[MYENV_NUM][LINE_SIZE]; //五个

const char* GetName()
{
    return getenv("USER");
}

const char* GetHostName()
{
    return getenv("HOSTNAME");
}


void GetPwd()
{
    getcwd(Pwd, sizeof(Pwd));//将路径放入缓冲区，命令行提示中，只有pwd经常变化
}


void Interaction(char*cmd,int size)
{
    GetPwd();
    printf("%s@%s:%s$ ",GetName(),GetHostName(),Pwd);
    char* str=fgets(cmd,size,stdin);
    if(str==NULL)
    {
        perror("fgets");
    }
    cmd[strlen(cmd)-1]='\0';
}

int Division(char* cmd,char*argv[])
{
    int argc=0;
    argv[argc++]=strtok(cmd,DELIM);
    while(argv[argc++]=strtok(NULL,DELIM));
    return argc-1;//有效个数
}

bool BUiltcmd(char*argv[],int argc)
{
    if (argc == 2 && (strcmp(argv[0], "cd") == 0))
    {
        chdir(argv[1]); // 切换路径
        GetPwd();
        return true;
    }
    else if ((strcmp(argv[0], "export") == 0)) // 导入环境变量
    {
        if (Env_Num == 5)
        {
             Env_Num = 0; // 最多放五个
        }  
        strcpy(Myenv[Env_Num], argv[1]);
        putenv(Myenv[Env_Num++]);
    }
    else if (argc == 2 && strcmp(argv[0], "echo") == 0)
    {
        // 查看退出码
        if ((strcmp(argv[1], "$?") == 0))
        {
            printf("%d\n", Exit_code);
            Exit_code = 0;
        }
        //此处只比较一个字符
        else if(*argv[1] == '$')//查看环境变量
        {
            char *env = getenv(argv[1]+1);
            if(env) printf("%s\n", env);
        }

        else
        {
            printf("%s\n", argv[1]);
        }
        return true;
    }
    return false;
}

void Executecmd(char* argv[],int argc)//bool检测是否为内建命令（0）
{
    pid_t pid=fork();
    if(pid==0)
    {
        //child
        //处理一下ls的高亮显示
        if((strcmp(argv[0],"ls")==0))
        {
            argv[argc++] = "--color";
            argv[argc] = NULL;
        }
        execvp(argv[0],argv);
        exit(EXEC_FAIL);
    }
    else
    {
        // father
        int status = 0;
        int rid = waitpid(pid, &status, 0);
        if (rid > 0)
        {
            if (WIFEXITED(status))
            {
                Exit_code = WEXITSTATUS(status);
            }
            else
            {
                // 被信号kill
                Sig = (status >> 7) & 0x7f;
            }
        }
    }
}

//简易shell

int main()
{
    char command[SIZE_CMD];
    char* argv[LINE_SIZE];
    Env_Num=0;
    while(1)//使用ctr+c退出吧
    {
        // 1:命令行提示&&获取指令
        Interaction(command, sizeof(command));
        // 2：分割命令
        int argc=Division(command, argv);
        // test
        // for (int i = 0; argv[i]; i++)
        // {
        //     printf("[%d]->%s\n", i, argv[i]);
        // }
        // 3：内建命令
        if(BUiltcmd(argv,argc))continue;//处理了内建就不需要fork，exec了
        // 4：fork执行命令
        Executecmd(argv,argc);
    }
    return 0;
}